﻿using Futuret.Core.DependencyInjection.Dependencies;
using Futuret.Core.Extensions;
using Futuret.Core.Futuret.Interface;
using Microsoft.Extensions.DependencyModel;

namespace Futuret.Core.Futuret;

/// <summary>
///     Author: Riva
///     Date: 2023/7/11 13:59
///     Description:
/// </summary>
public class AppInfo : IAppInfo
{
    /// <summary>
    ///     静态ServiceInfo对象
    /// </summary>
    private static AppInfo? _instance;

    /// <summary>
    ///     锁
    /// </summary>
    private static readonly object _lockObj = new();

    /// <summary>
    ///     Id
    /// </summary>
    public string Id { get; private init; } = string.Empty;

    /// <summary>
    ///     服务名
    /// </summary>
    public string ServiceName { get; private init; } = string.Empty;

    /// <summary>
    ///     授权策略
    /// </summary>
    public string CorsPolicy { get; set; } = string.Empty;

    /// <summary>
    ///     服务短名
    /// </summary>
    public string ShortName { get; private init; } = string.Empty;

    /// <summary>
    ///     根地址
    /// </summary>
    public string RelativeRootPath { get; private init; } = string.Empty;

    /// <summary>
    ///     版本
    /// </summary>
    public string Version { get; private init; } = string.Empty;

    /// <summary>
    ///     描述
    /// </summary>
    public string Description { get; private init; } = string.Empty;

    /// <summary>
    ///     有效程序集
    /// </summary>
    public IEnumerable<Assembly> AllAssemblies { get; private init; } = default!;

    /// <summary>
    ///     所有类型
    /// </summary>
    public IEnumerable<Type> AllTypes { get; private init; } = default!;

    /// <summary>
    ///     存储根服务，可能为空
    /// </summary>
    public IServiceProvider? rootServices { get; set; }

    /// <summary>
    ///     全局配置选项
    /// </summary>
    public IConfiguration? configuration { get; set; }

    /// <summary>
    ///     IServiceCollection
    /// </summary>
    public IServiceCollection? serviceCollection { get; set; }

    /// <summary>
    ///     IWebHostEnvironment
    /// </summary>
    public IWebHostEnvironment? webHostEnvironment { get; set; }

    /// <summary>
    ///     创建AppInfo
    /// </summary>
    /// <param name="startAssembly"></param>
    /// <returns></returns>
    public static AppInfo CreateInstance(Assembly startAssembly)
    {
        if (_instance != null) return _instance;

        lock (_lockObj)
        {
            if (_instance != null) return _instance;

            if (startAssembly == null)
                startAssembly = Assembly.GetExecutingAssembly() ??
                                throw new NullReferenceException(nameof(startAssembly));
            //有效程序集
            var _assemblies = GetAssemblies(startAssembly);
            //获取描述
            var attribute = startAssembly.GetCustomAttribute<AssemblyDescriptionAttribute>();
            var description = attribute is null ? string.Empty : attribute.Description;
            //程序名
            var assemblyName = startAssembly.GetName();
            //版本
            var version = assemblyName.Version ?? throw new NullReferenceException(nameof(assemblyName.Version));
            //服务名
            var fullName = assemblyName.Name?.ToLower() ?? string.Empty;
            var serviceName = fullName.Replace(".", "-");
            //标识符id
            var ticksHex = Guid.NewGuid().ToString("N");
            var envName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")?.ToLower();
            var serviceId = envName switch
            {
                "production" => $"{serviceName}-dev-{ticksHex}",
                "development" => $"{serviceName}-{ticksHex}",
                _ => throw new NotImplementedException("ASPNETCORE_ENVIRONMENT IS NULL")
            };
            var names = fullName.Split(".");
            _instance = new AppInfo
            {
                Id = serviceId,
                ServiceName = serviceName,
                ShortName = $"{names[^2]}-{names[^1]}",
                RelativeRootPath = $"{names[^2]}/{names[^1]}",
                CorsPolicy = "default",
                Description = description,
                Version = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}",
                AllAssemblies = _assemblies.Item1,
                AllTypes = _assemblies.Item2
            };
            return _instance;
        }
    }

    /// <summary>
    ///     赋值元素值
    /// </summary>
    public static void AddElement(Action<AppInfo> action)
    {
        AppInfo appInfo = new();
        action(appInfo);

        var app = GetInstance();
        app.rootServices = appInfo.rootServices ?? app.rootServices;
        app.configuration = appInfo.configuration ?? app.configuration;
        app.serviceCollection = appInfo.serviceCollection ?? app.serviceCollection;
        app.webHostEnvironment =
            appInfo.webHostEnvironment ?? app.webHostEnvironment;
    }

    /// <summary>
    ///     加载程序集中的所有类型
    /// </summary>
    /// <param name="ass"></param>
    /// <returns></returns>
    private static IEnumerable<Type> GetTypes(Assembly ass)
    {
        var types = Array.Empty<Type>();
        try
        {
            types = ass.GetTypes();
        }
        catch
        {
            Console.WriteLine($"Error load `{ass.FullName}` assembly.");
        }

        return types.Where(u => u.IsPublic && !u.IsDefined(typeof(IgnoreDependencyAttribute), false));
    }

    /// <summary>
    ///     获取应用有效程序集
    /// </summary>
    /// <returns></returns>
    private static (IEnumerable<Assembly>, IEnumerable<Type>) GetAssemblies(Assembly startAssembly)
    {
        IEnumerable<Assembly> scanAssemblies = Array.Empty<Assembly>();
        // 获取入口程序集
        var entryAssembly = startAssembly ?? throw new NullReferenceException(nameof(startAssembly));
        ;

        // 非独立发布/非单文件发布
        if (!string.IsNullOrWhiteSpace(entryAssembly?.Location))
        {
            var dependencyContext = DependencyContext.Default;

            scanAssemblies = dependencyContext!.RuntimeLibraries
                .Where(x => x.Type == "project")
                .Select(u => ReflectionExtension.GetAssembly(u.Name));
        }

        //待扩展独立发布的项目文件
        var assemblies = scanAssemblies as Assembly[] ?? scanAssemblies.ToArray();
        return (assemblies, assemblies.SelectMany(GetTypes));
    }

    /// <summary>
    ///     获取ServiceInfo
    /// </summary>
    /// <returns></returns>
    /// <exception cref="NullReferenceException"></exception>
    public static AppInfo GetInstance()
    {
        if (_instance is null)
            throw new NullReferenceException(nameof(AppInfo));

        return _instance;
    }

    /// <summary>
    ///     查找指定条件的类型
    /// </summary>
    public static IEnumerable<Type> FindTypes(Func<Type, bool> predicate)
    {
        return GetInstance().AllTypes.Where(predicate).ToArray();
    }

    /// <summary>
    ///     查找指定条件的类型
    /// </summary>
    public static Assembly[] FindAllItems(Func<Assembly, bool> predicate)
    {
        return GetInstance().AllAssemblies.Where(predicate).ToArray();
    }
}